package cn.texous.starter.sms.handler;

import cn.texous.starter.sms.config.properties.SmsProperties;
import cn.texous.starter.sms.config.properties.YunZhiXunSmsProperties;
import cn.texous.starter.sms.model.SendInfo;
import cn.texous.starter.sms.model.SendResult;
import cn.texous.starter.sms.model.YunZhiXunResponse;
import cn.texous.starter.sms.utils.HttpClientUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2019/8/23 10:55
 */
@Slf4j
public class YunZhiXunSmsHandler implements SmsHandler {
    private static final String CHANNEL = "yunZhiXun-sms";

    private SmsProperties smsProperties;
    private YunZhiXunSmsProperties yunZhiXunSmsProperties;

    public YunZhiXunSmsHandler(SmsProperties smsProperties) {
        this.smsProperties = smsProperties;
        this.yunZhiXunSmsProperties = smsProperties.getYunZhiXun();
    }

    @Override
    public SendResult send(SendInfo sendInfo) {
        SendResult sendResult = new SendResult(CHANNEL);
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("sid", yunZhiXunSmsProperties.getRegionId());
            jsonObject.put("token", yunZhiXunSmsProperties.getAccessSecret());
            jsonObject.put("appid", yunZhiXunSmsProperties.getAccessKeyId());
            jsonObject.put("templateid", smsProperties
                    .getTemplate().getYunZhiXun().get(sendInfo.getTemplate()));
            jsonObject.put("param", getParam(parserToMap(sendInfo.getParams(), true)));
            jsonObject.put("mobile", sendInfo.getMobile());
            jsonObject.put("uid", "demosmssendTexous");

            String body = jsonObject.toJSONString();

            System.out.println("body = " + body);

            String url = getStringBuffer().append("/sendsms").toString();
            String result = HttpClientUtil.postJson(url, body, null);
            YunZhiXunResponse yunZhiXunResponse
                    = new Gson().fromJson(result, YunZhiXunResponse.class);
            if (yunZhiXunResponse != null && "000000".equals(yunZhiXunResponse.getCode())) {
                log.info("云之信 短信发送成功！");
                sendResult.setCode(SendResult.SUCCESS);
                return sendResult;
            }
            log.error("云之讯 短信发送失败：{}", new Gson().toJson(sendInfo));
            generatorErrorMessage(sendResult, yunZhiXunResponse);

        } catch (Exception e) {
            log.error(String.format("云之讯 短信发送失败：%s", e.getMessage()), e);
            sendResult.setErrorCode("0");
            sendResult.setErrorMsg("短信验证码发送失败！");
        }
        return sendResult;
    }

    @Override
    public String channel() {
        return CHANNEL;
    }

    @Override
    public boolean init() {
        return yunZhiXunSmsProperties.getInit();
    }

    @Override
    public int order() {
        return yunZhiXunSmsProperties.getOrder();
    }

    private StringBuffer getStringBuffer() {
        StringBuffer sb = new StringBuffer("https://");
        sb.append(yunZhiXunSmsProperties.getDomain()).append("/ol/sms");
        return sb;
    }

    private String getParam(Map<String, String> param) {
        if (param == null || param.isEmpty())
            return null;
        Set<String> keys = param.keySet();

        List<Integer> keyInts = keys.stream()
                .map(Integer::valueOf)
                .sorted()
                .collect(Collectors.toList());

        StringBuilder sb = new StringBuilder();
        for (Integer key : keyInts) {
            sb.append(param.get(String.valueOf(key))).append(",");
        }
        return sb.substring(0, sb.length() - 1);
    }


    private static void generatorErrorMessage(SendResult result, YunZhiXunResponse response) {
        String code = response.getCode();
        String message = errorCodeMap.get(code);
        result.setErrorCode(code);
        result.setErrorMsg(message);
    }

    private static Map<String, String> errorCodeMap = new HashMap<>();

    static {
        errorCodeMap.put("000000", "OK");
        errorCodeMap.put("100001", "账户余额/套餐包余额不足, 请及时充值或购买套餐包");
        errorCodeMap.put("100005", "发送请求的IP不在白名单内。"
                + "访问IP不在白名单之内，可在后台 应用管理→点击需要设置的应用→编辑→服务器白名单 里添加该IP");
        errorCodeMap.put("100008", "手机号码不能为空。请输入标准的国内手机号码");
        errorCodeMap.put("100009", "手机号为受保护的号码。不可向该号码发送短信");
        errorCodeMap.put("100015", "号码不合法。请输入标准的国内手机号码");
        errorCodeMap.put("100016", "账号余额被冻结。请联系客服");
        errorCodeMap.put("100017", "余额已注销。请联系客服");
        errorCodeMap.put("100019", "应用可用额度余额不足。调大应用可用余额，后台→应用管理→可用额度");
        errorCodeMap.put("100699", "系统内部错误。请联系客服");
        errorCodeMap.put("101105", "主账户sid存在非法字符。可在后台首页获取“Account Sid”");
        errorCodeMap.put("101108", "开发者账户已注销。请联系客服");
        errorCodeMap.put("101109", "主账户sid未激活。请联系客服");
        errorCodeMap.put("101110", "主账户sid已锁定。请联系客服");
        errorCodeMap.put("101111", "主账户sid不存在。可在后台首页获取“Account Sid”");
        errorCodeMap.put("101112", "主账户sid为空。可在后台首页获取“Account Sid”");
        errorCodeMap.put("101117", "缺少token参数或参数为空。参数token，可从后台首页获取“Auth Token”");
        errorCodeMap.put("102100", "应用appid为空。获取路径后台→应用管理→点击需要对接应用，查看appId");
        errorCodeMap.put("102101", "应用appid存在非法字符。获取路径后台→应用管理→点击需要对接应用，查看appId");
        errorCodeMap.put("102102", "应用appid不存在。获取路径后台→应用管理→点击需要对接应用，查看appId");
        errorCodeMap.put("102103", "应用未上线。请先上线应用");
        errorCodeMap.put("102105", "应用appid不属于该主账号。获取路径后台→应用管理→点击需要对接应用，查看appId");
        errorCodeMap.put("103126", "未上线应用只能使用白名单中的号码。"
                + "申请应用上线，或者将该号码加入测试白名单，可在后台应用管理→应用测试→添加号码，添加该手机号码");
        errorCodeMap.put("105110", "该appid下，此短信模板(templateid)不存在。"
                + "可在后台短信产品→选择接入的应用→短信模板-模板ID，查看该模板ID");
        errorCodeMap.put("105111", "短信模板(templateid)未审核通过。"
                + "等待审核，工作日时间内审核时间为15分钟。如审核不通过可咨询在线客服");
        errorCodeMap.put("105112", "请求的参数(param)与模板上的变量数量不一致。"
                + "参数param上的数量与模板中的变量数量不一致，多个参数使用英文逗号隔开（如：param=“a,b,c”）");
        errorCodeMap.put("105113", "短信模板(templateid)不能为空。可在后台短信产品→选择接入的应用→短信模板-模板ID，查看该模板ID");
        errorCodeMap.put("105115", "短信类型(type)长度应为1个字符。短信类型错误，"
                + "类型：0:通知短信、5:会员服务短信、4:验证码短信(此类型content内必须至少有一个参数{1})");
        errorCodeMap.put("105117", "短信模板(templateid)含非法字符。可在后台短信产品→选择接入的应用→短信模板-模板ID，查看该模板ID");
        errorCodeMap.put("105118", "短信模板有替换内容，但缺少param参数或参数为空。请按照param的规则提供参数值");
        errorCodeMap.put("105119", "每个参数的长度不能超过100字。减少参数长度");
        errorCodeMap.put("105120", "群发号码单次提交不能超过100个。减少单次群发号码，将号码限制为100各以内");
        errorCodeMap.put("105121", "短信模板(templateid)已删除。已被删除，请重新创建模板");
        errorCodeMap.put("105124", "短信模板内容为空。填写模板内容");
        errorCodeMap.put("105125", "创建短信模板失败。联系客服");
        errorCodeMap.put("105126", "短信模板名称格式错误。短信模板名称，限20位长度");
        errorCodeMap.put("105128", "短信模板(templateid)不能为空。可在后台短信产品→选择接入的应用→短信模板-模板ID，查看该模板ID");
        errorCodeMap.put("105133", "短信内容过长，超过500字。减少短信长度");
        errorCodeMap.put("105134", "参数(param)中含有超过一对【】。短信内容只能包含一对【】且不能只有短信签名，短信签名只能在开头或结尾");
        errorCodeMap.put("105135", "参数(param)中含有特殊符号。参数中不能含有特殊符号，例如“【】”");
        errorCodeMap.put("105136", "签名长度应为2到12位。签名长度为2到12位");
        errorCodeMap.put("105138", "群发号码重复。对群发号码去重");
        errorCodeMap.put("105140", "账号未认证。请先申请认证，后台→账号设置");
        errorCodeMap.put("105141", "主账号需为企业认证。请升级认证为企业开发者，后台→账号设置");
        errorCodeMap.put("105142", "模板被定时群发任务锁定暂无法修改。停止占用该模板的定时群发任务");
        errorCodeMap.put("105143", "模板不属于该用户。请填写正确的模板ID，可在后台短信产品→选择接入的应用→短信模板-模板ID，查看该模板ID");
        errorCodeMap.put("105144", "创建验证码模板短信需带参数。当type=4时类型为验证码模板，需要带至少一个参数{1}");
        errorCodeMap.put("105145", "签名(autograph)格式错误。限2-12个汉字、英文字母和数字，不能纯数字");
        errorCodeMap.put("105146", "短信类型(type)错误。短信类型错误，类型：0:通知短信、"
                + "5:会员服务短信、4:验证码短信(此类型content内必须至少有一个参数{1})");
        errorCodeMap.put("105147", "对同个号码发送短信超过限定频率。查看是否被盗刷接口，"
                + "客户端侧需要增加图片/滑块验证码，如您是用于告警等合法场景，请联系客服");
        errorCodeMap.put("105150", "短信发送频率过快。降低请求发起频率");
        errorCodeMap.put("105152", "请求的参数(param)格式错误。请使用utf-8");
        errorCodeMap.put("105153", "手机号码格式错误。请输入标准的国内手机号码");
        errorCodeMap.put("105154", "短信服务请求异常e100。请联系客服");
        errorCodeMap.put("105155", "缺少签名(autograph)参数或参数为空。请提供签名,建议使用公司名/APP名/网站名");
        errorCodeMap.put("105156", "查询短信类型错误。查询的短信类型，默认为0，"
                + "获取验证通知及会员营销短信记录；1，只获取验证通知类短信；2，只能获取会员营销短信记录。");
        errorCodeMap.put("105157", "变量数量超过100个。减少变量数量");
        errorCodeMap.put("105158", "接口不支持GET方式调用。请按提示或者文档说明的方法调用，一般为POST");
        errorCodeMap.put("105159", "接口不支持POST方式调用。请按提示或者文档说明的方法调用，一般为GET");
        errorCodeMap.put("105161", "开始时间错误。短信发送结束时间,格式YYYYMMDDhhmmss");
        errorCodeMap.put("105162", "结束时间错误。短信发送开始时间,格式YYYYMMDDhhmmss，结束时间不能早于开始时间");
        errorCodeMap.put("105163", "超过可查询时间范围。暂时只能查询一天的数据");
        errorCodeMap.put("105164", "页码错误。请不要超出总页数");
        errorCodeMap.put("105165", "每页个数错误，限制访问(1-100)。每页可获取的数量为1-100个");
        errorCodeMap.put("105166", "请求频率过快。降低请求频率");
        errorCodeMap.put("105167", "uid格式错误或超过60位。不要使用特殊符号，并且长度控制在60位内");
        errorCodeMap.put("105168", "参数sid或token错误。sid和token从后台首页获取“Auth Token”，“Account Sid”");
        errorCodeMap.put("105169", "超过页码数。减少页码数");
        errorCodeMap.put("300001", "提交失败。请联系客服");
        errorCodeMap.put("300002", "未知。请联系客服");
        errorCodeMap.put("300003", "空号。请核对手机号码");
        errorCodeMap.put("300004", "黑名单。请联系客服");
        errorCodeMap.put("300005", "超频。按限定的提交频率提交短信。"
                + "同一个手机号1分钟内不能超过2条，24小时内验证类不能超过8条，通知类不能超过10条");
        errorCodeMap.put("300006", "系统忙。请联系客服");
    }
}
